﻿#pragma once

#include "DecoderPlugin.h"
#include "iostream"
#include <map>
#include <string>
#include <mutex>
#include <algorithm>
#include "DllLoader.h"

using namespace std;

typedef enum{
	DECODE_ROTATE_NONE,
	DECODE_ROTATE_LEFT,
	DECODE_ROTATE_RIGHT
}DECODE_ROTATE_TYPE;

typedef enum{
	DECODE_MIRROR_NONE,
	DECODE_MIRROR_H,
	DECODE_MIRROR_V
}DECODE_MIRROR_TYPE;

class DllDecoderPlugin :public DecoderPlugin
{
public:
	DllDecoderPlugin(const std::wstring& modname);
	virtual ~DllDecoderPlugin();

	void import();

	virtual bool Inited();
	virtual void Close();
	virtual int Decode(unsigned char *dest, int dest_buf_len, unsigned char *source, int color_depth, int column, int line, DecodeRequestStruct* args);
	virtual void GetDecodedParam(DecodedParam orig_param, int &new_color_depth, int &new_column, int &new_line, DecodeRequestStruct* args);
	const wchar_t* Name();
	const wchar_t* ErrorInfo();//err of the plugin

	virtual bool SetLsb(int lsb);
	virtual int GetLsb();

	wstring &LastError() { return _err; }
private:
	PluginProc m_proc;
	CDllLoader m_loader;
	DecoderPlugin *m_plugin;
};

class DecoderPluginMgr
{
private:
	DecoderPluginMgr();
	DecoderPluginMgr(const DecoderPluginMgr&){}
	DecoderPluginMgr& operator=(const DecoderPluginMgr&){}
	~DecoderPluginMgr();

	int RescanPlugins(string path, std::map<wstring, DecoderPlugin*> &plugin_map);
	void SetDefaultDecoder();
public:
	static DecoderPluginMgr* getInstance()
	{
		static DecoderPluginMgr _instance;
		return &_instance;
	}

	std::map<wstring, DecoderPlugin*> &getDecoders()
	{
		return decoders;
	}
	std::map<wstring, DecoderPlugin*> &getReadFormats()
	{
		return read_formats;
	}
	DecoderPlugin* getDecoder(wstring name){
		try{
			return decoders.at(name);
		} catch (std::out_of_range&){
			return decoders.at(default_decoder);
		}
	}
	DecoderPlugin* getReadFormat(wstring name)
	{
		try {
			return read_formats.at(name);
		} catch (std::out_of_range&) {
			return read_formats.at(default_read_format);
		}
	}

	wstring &getDefaultDecoderName()
	{
		return default_decoder;
	}
	wstring &getDefaultReadFormatName()
	{
		return default_read_format;
	}
private:
	std::map<wstring, DecoderPlugin*> decoders;
	std::map<wstring, DecoderPlugin*> read_formats;
	wstring default_decoder;
	wstring default_read_format;
};